#pragma comment( linker, "/defaultlib:ws2_32.lib" )

#include "server.h"

using namespace std;

bool server::fileExist(const string &fileName)
{
	ifstream file(fileName);
	if (file.good())
	{
		file.close();
		return true;
	}
	else
	{
		file.close();
		return false;
	}
}

int server::getFileSize(const string &fileName)
{
	ifstream file(fileName, ifstream::binary);
	file.seekg(0, file.end);
	int size = file.tellg();
	file.close();
	return size;
}

bool server::isBinaryFile(const string &fileName)
{
	int c;
	ifstream file(fileName);
	while ((c = file.get()) != EOF && c <= 127)
		;
	if (c == EOF)
	{
		file.close();
		return false;
	}
	else
	{
		file.close();
		return true;
	}
}

int server::getTextFileCount(const string &fileName)
{
	ifstream file(fileName);
	int count = 0;
	while (true)
	{
		int position = 0;
		while (!file.eof())
		{
			char c = file.get();
			if (c != EOF)
			{
				position++;
				if (position == DATA_SIZE - 1)
				{
					break;
				}
			}
		}
		count++;
		if (file.eof())
		{
			break;
		}
	}
	file.close();
	return count;
}

int server::getNextSequenceNumber(int sequenceNumber)
{
	if (sequenceNumber == 1)
	{
		return 0;
	}
	else
	{
		return 1;
	}
}


vector<string> server::listDirectoryContents(const char *sDir)
{
	vector<string> vec;
	WIN32_FIND_DATA fdFile;
	HANDLE hFind = NULL;

	char sPath[2048];

	//Specify a file mask. *.* = We want everything!
	sprintf_s(sPath, "%s\\*.*", sDir);

	TCHAR tchar[2048];
	for (int i = 0; i < 2048; i++)
	{
		tchar[i] = sPath[i];
	}
	if ((hFind = FindFirstFile(tchar, &fdFile)) == INVALID_HANDLE_VALUE)
	{
		printf("Path not found: [%s]\n", sDir);
		return vec;
	}

	do
	{
		//Find first file will always return "."
		//    and ".." as the first two directories.
		if (strcmp((const char*)fdFile.cFileName, ".") != 0
			&& strcmp((const char*)fdFile.cFileName, "..") != 0)
		{
			//Build up our file path using the passed in
			//  [sDir] and the file/foldername we just found:
			sprintf_s(sPath, "%s\\%s", sDir, fdFile.cFileName);

			//Is the entity a File or Folder?
			if (fdFile.dwFileAttributes &FILE_ATTRIBUTE_DIRECTORY)
			{
				//printf("Directory: %s\n", sPath);
				//ListDirectoryContents(sPath); //Recursion, I love it!
			}
			else
			{
				string fileName = sPath;
				int index = fileName.find_last_of("\\");
				string fileName2 = fileName.substr(index + 1, fileName.length() - index - 1);
				vec.push_back(fileName2);
				//printf("File: %s\n", fileName2.c_str());
			}
		}
	} while (FindNextFile(hFind, &fdFile)); //Find the next file.
	FindClose(hFind); //Always, Always, clean things up!
	return vec;
}

int server::stringToInt(string s)
{
	istringstream stringBuffer(s);
	int value;
	stringBuffer >> value;
	return value;
}

server::server(char *fn)
{
	addrSize = sizeof(remaddr);
	WSADATA wsadata;
	if (WSAStartup(0x0202, &wsadata) != 0)
	{
		std::cout << "error in starting WSAStartup()" << endl;
		exit(1);
	}
	/* display the wsadata structure */
	std::cout << endl
		<< "wsadata.wVersion " << wsadata.wVersion << endl
		<< "wsadata.wHighVersion " << wsadata.wHighVersion << endl
		<< "wsadata.szDescription " << wsadata.szDescription << endl
		<< "wsadata.szSystemStatus " << wsadata.szSystemStatus << endl
		<< "wsadata.iMaxSockets " << wsadata.iMaxSockets << endl
		<< "wsadata.iMaxUdpDg " << wsadata.iMaxUdpDg << endl;

	//Display info of local host
	char localhost[32];
	gethostname(localhost, 31);
	std::cout << "hostname: " << localhost << endl;

	HOSTENT *hp;
	if ((hp = gethostbyname(localhost)) == NULL) {
		std::cout << "gethostbyname() cannot get local host info?"
			<< WSAGetLastError() << endl;
		exit(1);
	}

	//create the server socket
	if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET)
	{
		std::cout << "can not create socket" << endl;
		exit(1);
	}

	myaddr.sin_family = AF_INET;
	myaddr.sin_addr.s_addr = htonl(INADDR_ANY);
	myaddr.sin_port = htons(SERVER_PORT);

	//Bind the server port
	if (bind(fd, (struct sockaddr *)&myaddr, sizeof(myaddr)) < 0)
	{
		std::cout << "can not bind socket" << endl;
		exit(1);
	}

	fout.open(fn);
	run();
}

server::~server()
{
	closesocket(fd);
	WSACleanup();
	fout.close();
}

void server::run()
{
	struct timeval timeouts;
	timeouts.tv_sec = 0;
	timeouts.tv_usec = 300000;

	bool handShakeSucceed = false;
	int initialSequenceNumber;
	int random;
	
	while (true)
	{
		char buf[sizeof(myPacket)];
		int recvlen = recvfrom(fd, buf, sizeof(myPacket), 0, (sockaddr *)&remaddr, &addrSize);
		myPacket *mp;
		mp = (myPacket*)malloc(sizeof(myPacket));
		mp = (myPacket*)buf;
		//receive first handshake packet
		if (mp->sequenceNumber == -100)
		{
			std::cout << "first handshake packet received:" << mp->data << endl;
			if (TRACE)
			{
				fout << "Receiver: handshake packet 1 received "  <<mp->data<< endl;
				fout.flush();
			}
			initialSequenceNumber =  stringToInt(string(mp->data));
			srand(time(NULL));
			random = rand() % 256;
			std::cout << "random generated:" << random << endl;
			myPacket *mp1;
			mp1 = (myPacket*)malloc(sizeof(myPacket));
			mp1->sequenceNumber = mp->sequenceNumber;
			mp1->acknowledgement = true;
			string reply = string(mp->data) + "," + std::to_string(random);
			strcpy_s(mp1->data, reply.c_str());
			std::cout << "second handshake packet to send:" << mp1->data << endl;
			if (TRACE)
			{
				fout << "Receiver: sent handshake packet 2 "  << mp1->data<<endl;
				fout.flush();
			}
			char * replyBuf = (char*)mp1;
			sendto(fd, replyBuf, sizeof(myPacket), 0, (SOCKADDR *)&remaddr, addrSize);
		}
		//receive third handshake packet
		else if (mp->sequenceNumber == -101)
		{
			std::cout << "third handshake packet receive:" << mp->data << endl;
			if (TRACE)
			{
				fout << "Receiver: handshake packet 3 received "  <<mp->data<< endl;
				fout.flush();
			}
			int number = stringToInt(string(mp->data));
			if(number == random)
			{
				handShakeSucceed = true;
				std::cout << "handshake succeed" << endl;
				if (TRACE)
				{
					fout << "Receiver: handshake succeeded "  << endl;
					fout.flush();
				}
			}
			myPacket *mp1;
			mp1 = (myPacket*)malloc(sizeof(myPacket));
			mp1->sequenceNumber = mp->sequenceNumber;
			mp1->acknowledgement = true;
			char * replyBuf = (char*)mp1;
			sendto(fd, replyBuf, sizeof(myPacket), 0, (SOCKADDR *)&remaddr, addrSize);
		}
		// receive get/put/list command packet
		else
		{
			if (handShakeSucceed)
			{
				//check sequence number
				if (mp->sequenceNumber == random)
				{
					if (TRACE)
					{
						char localhost[32];
						gethostname(localhost, 31);
						fout << "Receiver: Starting on host " << localhost << endl;
						fout.flush();
					}
					if (TRACE)
					{
						fout << "Receiver: received packet " << mp->sequenceNumber << endl;
						fout.flush();
					}
					string text(mp->data);
					//put
					if (text.find("operation:put") == 0)
					{
						cout << "text received:" << text << endl;
						int rcvNum = 1; //include previous control packet
						int firstSplitterIndex = text.find_first_of("|");
						int secondSplitterIndex = firstSplitterIndex + 1 + text.substr(firstSplitterIndex + 1).find_first_of("|");
						int thirdSplitterIndex = secondSplitterIndex + 1 + text.substr(secondSplitterIndex + 1).find_first_of("|");
						int fourthSplitterIndex = thirdSplitterIndex + 1 + text.substr(thirdSplitterIndex + 1).find_first_of("|");
						string userName = text.substr(firstSplitterIndex + 10, secondSplitterIndex - firstSplitterIndex - 10);
						string fileName = text.substr(secondSplitterIndex + 10, thirdSplitterIndex - secondSplitterIndex - 10);
						string countStr = text.substr(thirdSplitterIndex + 7, fourthSplitterIndex - thirdSplitterIndex - 7);
						int count = stringToInt(countStr);
						string binaryStr = text.substr(fourthSplitterIndex + 8);
						bool isBinaryFile = (binaryStr == "1") ? true : false;
						
						//response to control packet
						myPacket *mp2;
						mp2 = (myPacket*)malloc(sizeof(myPacket));
						mp2->sequenceNumber = mp->sequenceNumber;
						mp2->acknowledgement = true;
						cout << "file name:" + fileName << endl;
						if(fileExist(fileName))
						{
							mp2->duplicate = true;
							cout<<"File name duplicated"<<endl;
						}
						else
						{
							mp2->duplicate = false;
						}
						char * replyBuf = (char*)mp2;
						sendto(fd, replyBuf, sizeof(myPacket), 0, (sockaddr *)&remaddr, addrSize);
						if (TRACE)
						{
							fout << "Receiver: send an ACK for packet " << mp->sequenceNumber << endl;
							fout.flush();
						}
						// receive put command packet again
						if (mp2->duplicate)
						{
							continue;
						}

						std::cout << "User \"" + userName + "\" requested to put file " + fileName << endl;
						int expectedSequenceNumber = mp->sequenceNumber+1;
						//response to data packets
						ofstream ofs;
						int loopNum = 0;
						while (true)
						{
							recvlen = recvfrom(fd, buf, sizeof(myPacket), 0, (sockaddr *)&remaddr, &addrSize);
							if (recvlen > 0)
							{
								myPacket *mp;
								mp = (myPacket*)malloc(sizeof(myPacket));
								mp = (myPacket*)buf;
								cout << "sequence number received:" << mp->sequenceNumber << endl;
								if (TRACE)
								{
									fout << "Receiver: received packet " << mp->sequenceNumber << endl;
									fout.flush();
									rcvNum++;
								}
								//control packet received again 
								if (mp->sequenceNumber == random)
								{
									sendto(fd, replyBuf, sizeof(myPacket), 0, (sockaddr *)&remaddr, addrSize);
								}
								//terminate packet
								else if (mp->sequenceNumber == expectedSequenceNumber && mp->terminate)
								{
									cout << "terminate packet" << endl;
									break;
								}
								//old packet
								else if (mp->sequenceNumber < expectedSequenceNumber && (!mp->terminate))
								{
									myPacket *mp2;
									mp2 = (myPacket*)malloc(sizeof(myPacket));
									mp2->sequenceNumber = mp->sequenceNumber;
									mp2->acknowledgement = true;
									char * replyBuf = (char*)mp2;
									if (TRACE)
									{
										fout << "Receiver: send an ACK for packet " << mp->sequenceNumber << endl;
										fout.flush();
									}
									sendto(fd, replyBuf, sizeof(myPacket), 0, (sockaddr *)&remaddr, addrSize);
								}
								//expected non-terminate packet
								else if (mp->sequenceNumber == expectedSequenceNumber && (!mp->terminate))
								{
									//create file when receiving file data at first time
									if (loopNum == 0)
									{
										if (isBinaryFile)
										{
											std::cout << "create binary file" << endl;
											ofs = ofstream(fileName, ofstream::binary);
										}
										else
										{
											std::cout << "create text file" << endl;
											ofs = ofstream(fileName, ofstream::out);
										}
										loopNum++;
									}

									cout << "correct sequence number:" << mp->sequenceNumber << endl;
									//response
									myPacket *mp2;
									mp2 = (myPacket*)malloc(sizeof(myPacket));
									mp2->sequenceNumber = mp->sequenceNumber;
									mp2->acknowledgement = true;
									char * replyBuf = (char*)mp2;
									if (TRACE)
									{
										fout << "Receiver: send an ACK for packet " << mp->sequenceNumber << endl;
										fout.flush();
									}
									sendto(fd, replyBuf, sizeof(myPacket), 0, (sockaddr *)&remaddr, addrSize);
									expectedSequenceNumber++;
									char szbuffer[DATA_SIZE];
									memset(szbuffer, '\0', DATA_SIZE);
									if (isBinaryFile)
									{
										std::memcpy(szbuffer, mp->data, mp->dataSize);
										ofs.write(szbuffer, mp->dataSize);
									}
									else
									{
										strcpy_s(szbuffer, mp->dataSize + 1, mp->data);
										ofs << szbuffer;
									}
									ofs.flush();
								}
								//unexpected packet
								else
								{
									cout << "wrong seq, expected seq:" << expectedSequenceNumber << endl;
									//response
									myPacket *mp2;
									mp2 = (myPacket*)malloc(sizeof(myPacket));
									mp2->sequenceNumber = mp->sequenceNumber;
									mp2->acknowledgement = false;
									char * replyBuf = (char*)mp2;
									if (TRACE)
									{
										fout << "Receiver: send an ACK for packet " << mp->sequenceNumber << endl;
										fout.flush();
									}
									sendto(fd, replyBuf, sizeof(myPacket), 0, (sockaddr *)&remaddr, addrSize);
								}
							}
						}
						std::cout << "file completely received" << endl;
						if (TRACE)
						{
							fout << "Receiver: transfer completed " << endl
								<<"Receiver: number of bytes received:"<<rcvNum*sizeof(myPacket)<<endl;
							fout.flush();
						}
						ofs.close();
						cout << "file closed" << endl;
						//handShakeSucceed = false;
					}
					//get
					else if (text.find("operation:get") == 0)
					{
						int firstSplitterIndex = text.find_first_of("|");
						int secondSplitterIndex = firstSplitterIndex + 1 + text.substr(firstSplitterIndex + 1).find_first_of("|");
						string userName = text.substr(firstSplitterIndex + 10, secondSplitterIndex - firstSplitterIndex - 10);
						string fileName = text.substr(secondSplitterIndex + 10);
						std::cout << "User \"" + userName + "\" requested to get file " + fileName << endl;
						//file exist
						if (fileExist(fileName))
						{
							int effectivePacketNum = 0;
							int packetNum = 0;
							bool binaryFile = isBinaryFile(fileName);
							int binaryFlag = binaryFile ? 1 : 0;
							ifstream fin;
							int count;
							if (binaryFile)
							{
								int fileSize = getFileSize(fileName);
								count = fileSize % (DATA_SIZE - 1) == 0 ? fileSize / (DATA_SIZE - 1) : fileSize / (DATA_SIZE - 1) + 1;
								fin = ifstream(fileName, ifstream::binary);
							}
							else
							{
								count = getTextFileCount(fileName);
								fin = ifstream(fileName);
							}
							string result = "count:" + to_string(count) + "|binary:" + to_string(binaryFlag);
							//response to control packet
							myPacket *mp2;
							mp2 = (myPacket*)malloc(sizeof(myPacket));
							mp2->sequenceNumber = mp->sequenceNumber;
							mp2->acknowledgement = true;
							mp2->terminate = false;
							strcpy_s(mp2->data, result.c_str());
							char * replyBuf = (char*)mp2;
							if (TRACE)
							{
								fout << "Receiver: send an ACK for packet " << mp->sequenceNumber << endl;
								fout.flush();
							}
							sendto(fd, replyBuf, sizeof(myPacket), 0, (sockaddr *)&remaddr, addrSize);
							char * controlBuf = replyBuf;

							//send data packets
							std::cout << "begin to send file" << endl;
							int sequenceNumber = initialSequenceNumber;
							myPacket * arrayPoint = new myPacket[count];
							//binary file
							if (binaryFile)
							{
								//read file into an array
								for (int i = 0; i < count; i++)
								{
									char array[DATA_SIZE]; // allocating an array
									memset(array, '\0', DATA_SIZE);
									fin.read(array, DATA_SIZE - 1);
									int readSize = fin.gcount();
									myPacket * mp = arrayPoint + i;
									mp->sequenceNumber = sequenceNumber++;
									mp->terminate = false;
									mp->dataSize = readSize;
									memcpy(mp->data, array, readSize + 1);
								}
							}
							else
							{
								//read file into an array
								for (int i = 0; i < count; i++)
								{
									char array[DATA_SIZE]; // allocating an array
									memset(array, '\0', DATA_SIZE);
									int position = 0; //this will be used incremently to fill characters in the array 
									//this loop run until end of file (eof) does not occur
									while (!fin.eof())
									{
										char c = fin.get(); //reading one character from file to array
										if (c != EOF)
										{
											array[position] = c;
											position++;
											if (position == DATA_SIZE - 1)	//full
											{
												array[position] = '\0';
												break;
											}
										}
									}
									if (position != DATA_SIZE - 1)
									{
										array[position] = '\0';
									}
									myPacket * mp = arrayPoint + i;
									mp->sequenceNumber = sequenceNumber++;
									mp->terminate = false;
									mp->dataSize = strlen(array);
									strcpy_s(mp->data, strlen(array) + 1, array);
								}
							}
							//close file
							fin.close();
							
							//assign variables
							int base = initialSequenceNumber;
							int nextSeq = initialSequenceNumber;

							//send first WINDOW_SIZE packets
							for (int i = 0; i < WINDOW_SIZE; i++)
							{
								replyBuf = (char*)(arrayPoint + i);
								cout << "send sequence number:" << (arrayPoint + i)->sequenceNumber << endl;
								sendto(fd, replyBuf, sizeof(myPacket), 0, (sockaddr *)&remaddr, addrSize);
								if (TRACE)
								{
									fout << "Sender: send packet " << (arrayPoint + i)->sequenceNumber << endl;
									fout.flush();
									effectivePacketNum++;
									packetNum++;
								}
							}
							nextSeq += WINDOW_SIZE;

							//timer
							while (true)
							{
								fd_set readfds;
								FD_ZERO(&readfds);
								FD_SET(fd, &readfds);
								int outfds;
								//cout << "base:" << base << endl;
								//cout << "nextSeq:" << nextSeq << endl;
								//timeout, resend
								if (!(outfds = select(1, &readfds, NULL, NULL, &timeouts)))
								{
									//cout << "timeout" << endl;
									//resend
									for (int i = base - initialSequenceNumber; i < nextSeq - initialSequenceNumber; i++)
									{
										replyBuf = (char*)(arrayPoint + i);
										sendto(fd, replyBuf, sizeof(myPacket), 0, (sockaddr *)&remaddr, addrSize);
										//cout << "resend sequence number:" << (arrayPoint + i)->sequenceNumber << endl;
										if (TRACE)
										{
											fout << "Sender: timeout, resend packet " << (arrayPoint + i)->sequenceNumber << endl;
											fout.flush();
											packetNum++;
										}
									}
								}
								//not timeout
								if (outfds == 1)
								{
									//cout << "not timeout" << endl;
									char buffer[sizeof(myPacket)];
									recvfrom(fd, buffer, sizeof(myPacket), 0, (sockaddr *)&remaddr, &addrSize);
									myPacket *mp2;
									mp2 = (myPacket*)malloc(sizeof(myPacket));
									mp2 = (myPacket*)buffer;
									//check sequence number and acknowledgement
									if (mp2->acknowledgement)
									{
										if (TRACE)
										{
											fout << "Sender: received ACK for packet " << mp2->sequenceNumber << endl;
											fout.flush();
										}
										int ackSeqNum = mp2->sequenceNumber;
										//cout << "ACK sequence number:" << ackSeqNum << endl;
										//update base
										if (ackSeqNum >= base)
										{
											base = ackSeqNum + 1;
											//cout << "base increment:" << base << endl;
										}
										else
										{
											continue;
										}
										//send subsequent packets
										if (nextSeq<initialSequenceNumber+count && base+WINDOW_SIZE>nextSeq)
										{
											int upperBound = min(base + WINDOW_SIZE, initialSequenceNumber + count);
											//cout << "upperBound:" << upperBound << endl;
											for (int i = nextSeq - initialSequenceNumber; i < upperBound - initialSequenceNumber; i++)
											{
												replyBuf = (char*)(arrayPoint + i);
												//cout << "send sequence number:" << (arrayPoint + i)->sequenceNumber << endl;
												sendto(fd, replyBuf, sizeof(myPacket), 0, (sockaddr *)&remaddr, addrSize);
												if (TRACE)
												{
													fout << "Sender: send packet " << (arrayPoint + i)->sequenceNumber << endl;
													fout.flush();
													effectivePacketNum++;
													packetNum++;
												}
											}
											nextSeq = upperBound;
										}
										//receive ACK for last packet
										else if (ackSeqNum == initialSequenceNumber + count-1)
										{
											cout << "receive ACK for last seq num" << endl;
											break;
										}
									}
									else if (mp2->sequenceNumber==random && (!mp2->acknowledgement) )
									{
										sendto(fd, controlBuf, sizeof(myPacket), 0, (sockaddr *)&remaddr, addrSize);
									}
									else
									{
										cout << "NAK sequence number:" << mp2->sequenceNumber << endl;
									}
								}
							}

							//send terminate packet 10 times
							mp = (myPacket*)malloc(sizeof(myPacket));
							mp->sequenceNumber = sequenceNumber++;
							mp->terminate = true;
							char * buf = (char*)mp;
							for (int i = 0; i < 10; i++)
							{
								//cout << "sequence number:" << mp->sequenceNumber << endl;
								sendto(fd, buf, sizeof(myPacket), 0, (sockaddr *)&remaddr, addrSize);
							}
							delete[] arrayPoint;

							std::cout << "file completely transfered!" << endl;
							if (TRACE)
							{
								fout << "Sender: file transfer completed " << endl
									<< "Sender: number of effective packets sent: " << effectivePacketNum << endl
									<< "Sender: number of effective bytes sent:" << effectivePacketNum*sizeof(myPacket) << endl
									<< "Sender: number of packets sent: " << packetNum << endl
									<< "Sender: number of bytes sent: " << packetNum*sizeof(myPacket) << endl;
								fout.flush();
							}
						}
						//file not exist
						else
						{
							string result = "requested file not exist";
							std::cout << result << endl;
							//response to control packet
							myPacket *mp2;
							mp2 = (myPacket*)malloc(sizeof(myPacket));
							mp2->sequenceNumber = mp->sequenceNumber;
							mp2->acknowledgement = true;
							mp2->terminate = false;
							strcpy_s(mp2->data, result.c_str());
							char * replyBuf = (char*)mp2;
							sendto(fd, replyBuf, sizeof(myPacket), 0, (sockaddr *)&remaddr, addrSize);
						}
					}
					//list
					else if (text.find("operation:list") == 0)
					{
						int firstSplitterIndex = text.find_first_of("|");
						string userName = text.substr(firstSplitterIndex + 10);
						std::cout << "User \"" + userName + "\" requested to get file list in server" << endl;
						TCHAR infoBuf[200];
						if (!GetCurrentDirectory(200, infoBuf)){
							printf("GetCurrentDirectory() failed!\n");
						}
						string curDir = infoBuf;
						//printf("Your current directory is: %s\n", curDir.c_str());
						vector<string> vec = listDirectoryContents(curDir.c_str());
						string listResult = "";
						for (vector<string>::const_iterator ite = vec.begin(); ite != vec.end(); ++ite)
						{
							listResult += *ite;
							listResult += "\n";
						}
						int count = listResult.length() % (DATA_SIZE - 1) == 0 ? listResult.length() / (DATA_SIZE - 1) : (listResult.length() / (DATA_SIZE - 1) + 1);
						string text = "count:" + to_string(count);
						//std::cout << text << endl;

						//response to control packet
						myPacket *mp2;
						mp2 = (myPacket*)malloc(sizeof(myPacket));
						mp2->sequenceNumber = mp->sequenceNumber;
						mp2->acknowledgement = true;
						strcpy_s(mp2->data, text.c_str());
						char * replyBuf = (char*)mp2;
						if (TRACE)
						{
							fout << "Receiver: send an ACK for packet " << mp->sequenceNumber << endl;
							fout.flush();
						}
						sendto(fd, replyBuf, sizeof(myPacket), 0, (sockaddr *)&remaddr, addrSize);
						char * controlBuf = replyBuf;

						int effectivePacketNum = 0;
						int packetNum = 0;

						int sequenceNumber = initialSequenceNumber;
						myPacket * arrayPoint = new myPacket[count];
						for (int i = 0; i < count; i++)
						{
							myPacket *mp3 = arrayPoint + i;
							mp3->sequenceNumber = sequenceNumber++;
							mp3->acknowledgement = false;
							memset(mp3->data, '\0', DATA_SIZE);
							strcpy_s(mp3->data, listResult.substr((DATA_SIZE - 1)*i, DATA_SIZE - 1).c_str());
						}

						//assign variables
						int base = initialSequenceNumber;
						int nextSeq = initialSequenceNumber;

						int min = min(count, WINDOW_SIZE);
						for (int i = 0; i < min; i++)
						{
							replyBuf = (char*)(arrayPoint + i);
							//cout << "send sequence number:" << (arrayPoint + i)->sequenceNumber << endl;
							sendto(fd, replyBuf, sizeof(myPacket), 0, (sockaddr *)&remaddr, addrSize);
						}
						nextSeq += min;

						//timer
						while (true)
						{
							fd_set readfds;
							FD_ZERO(&readfds);
							FD_SET(fd, &readfds);
							int outfds;
							//cout << "base:" << base << endl;
							//cout << "nextSeq:" << nextSeq << endl;
							//timeout, resend
							if (!(outfds = select(1, &readfds, NULL, NULL, &timeouts)))
							{
								//cout << "timeout" << endl;
								//resend
								for (int i = base - initialSequenceNumber; i < nextSeq - initialSequenceNumber; i++)
								{
									replyBuf = (char*)(arrayPoint + i);
									sendto(fd, replyBuf, sizeof(myPacket), 0, (sockaddr *)&remaddr, addrSize);
									//cout << "resend sequence number:" << (arrayPoint + i)->sequenceNumber << endl;
									if (TRACE)
									{
										fout << "Sender: timeout, resend packet " << (arrayPoint + i)->sequenceNumber << endl;
										fout.flush();
										packetNum++;
									}
								}
							}
							//not timeout
							if (outfds == 1)
							{
								//cout << "not timeout" << endl;
								char buffer[sizeof(myPacket)];
								recvfrom(fd, buffer, sizeof(myPacket), 0, (sockaddr *)&remaddr, &addrSize);

								myPacket *mp2;
								mp2 = (myPacket*)malloc(sizeof(myPacket));
								mp2 = (myPacket*)buffer;
								//check sequence number and acknowledgement
								if (mp2->acknowledgement)
								{
									if (TRACE)
									{
										fout << "Sender: received ACK for packet " << mp2->sequenceNumber << endl;
										fout.flush();
									}
									int ackSeqNum = mp2->sequenceNumber;
									//cout << "ACK sequence number:" << ackSeqNum << endl;
									//update base
									if (ackSeqNum >= base)
									{
										base = ackSeqNum + 1;
										//cout << "base increment:" << base << endl;
									}
									else
									{
										continue;
									}
									//send subsequent packets
									if (nextSeq<initialSequenceNumber + count && base + WINDOW_SIZE>nextSeq)
									{
										int upperBound = min(base + WINDOW_SIZE, initialSequenceNumber + count);
										//cout << "upperBound:" << upperBound << endl;
										for (int i = nextSeq - initialSequenceNumber; i < upperBound - initialSequenceNumber; i++)
										{
											replyBuf = (char*)(arrayPoint + i);
											//cout << "send sequence number:" << (arrayPoint + i)->sequenceNumber << endl;
											sendto(fd, replyBuf, sizeof(myPacket), 0, (sockaddr *)&remaddr, addrSize);
											if (TRACE)
											{
												fout << "Sender: timeout, resend packet " << (arrayPoint + i)->sequenceNumber << endl;
												fout.flush();
												packetNum++;
											}
										}
										nextSeq = upperBound;
									}
									//receive ACK for last packet
									else if (ackSeqNum == initialSequenceNumber + count - 1)
									{
										//cout << "receive ACK for last seq num" << endl;
										break;
									}
								}
								else if (mp2->sequenceNumber == random && (!mp2->acknowledgement))
								{
									sendto(fd, controlBuf, sizeof(myPacket), 0, (sockaddr *)&remaddr, addrSize);
								}
								else
								{
									//cout << "NAK sequence number:" << mp2->sequenceNumber << endl;
								}
							}
						}

						//send terminate packet 10 times
						mp = (myPacket*)malloc(sizeof(myPacket));
						mp->sequenceNumber = sequenceNumber++;
						mp->terminate = true;
						char * buf = (char*)mp;
						for (int i = 0; i < 10; i++)
						{
							//cout << "sequence number:" << mp->sequenceNumber << endl;
							sendto(fd, buf, sizeof(myPacket), 0, (sockaddr *)&remaddr, addrSize);
						}
						delete[] arrayPoint;
						cout << "transfer complete" << endl;
						if (TRACE)
						{
							fout << "Sender: file transfer completed " << endl
								<< "Sender: number of effective bytes sent:" << effectivePacketNum*sizeof(myPacket) << endl
								<< "Sender: number of packets sent: " << packetNum << endl
								<< "Sender: number of bytes sent: " << packetNum*sizeof(myPacket) << endl;
							fout.flush();
						}
						handShakeSucceed = false;
					}
					else if (text.find("operation:rename") == 0)
					{
						int firstSplitterIndex = text.find_first_of("|");
						int secondSplitterIndex = firstSplitterIndex + 1 + text.substr(firstSplitterIndex + 1).find_first_of("|");
						int thirdSplitterIndex = secondSplitterIndex + 1 + text.substr(secondSplitterIndex + 1).find_first_of("|");				
						string userName = text.substr(firstSplitterIndex + 10, secondSplitterIndex - firstSplitterIndex - 10);
						string fileName = text.substr(secondSplitterIndex + 10, thirdSplitterIndex-secondSplitterIndex-10);
						string newName = text.substr(thirdSplitterIndex + 9);
						cout << "User " + userName + " requested to rename file " + fileName + ", new name is "<< newName << endl;						
						myPacket *mp2;
						mp2 = (myPacket*)malloc(sizeof(myPacket));
						mp2->sequenceNumber = mp->sequenceNumber;
						mp2->acknowledgement = true;
						if (fileExist(fileName)) //file exists
						{
							int result = rename(fileName.c_str(), newName.c_str());
							if (result == 0)
							{
								mp2->terminate = false;
							}
							else
							{
								mp2->terminate = true;
								string text = "rename file failed";
								strcpy_s(mp2->data, text.c_str());
							}
						}
						//file not exists
						else
						{
							mp2->terminate = true;
							string text = "file does not exist";
							strcpy_s(mp2->data, text.c_str());
						}

						char * replyBuf = (char*)mp2;
						for (int i = 0; i < 10; i++)
						{
							sendto(fd, replyBuf, sizeof(myPacket), 0, (sockaddr *)&remaddr, addrSize);
						}
					}
				}
				else
				{
					//cout << "sequence number:" << mp->sequenceNumber << endl;
					myPacket *mp2;
					mp2 = (myPacket*)malloc(sizeof(myPacket));
					mp2->sequenceNumber = mp->sequenceNumber;
					mp2->acknowledgement = true;
					mp2->terminate = true;
					string text = "sequence number is wrong";
					strcpy_s(mp2->data, text.c_str());
					char * replyBuf = (char*)mp2;
					sendto(fd, replyBuf, sizeof(myPacket), 0, (sockaddr *)&remaddr, addrSize);
				}
			}
			else
			{
				myPacket *mp2;
				mp2 = (myPacket*)malloc(sizeof(myPacket));
				mp2->sequenceNumber = mp->sequenceNumber;
				mp2->acknowledgement = true;
				mp2->terminate = true;
				string text = "handshake failed at server";
				strcpy_s(mp2->data,text.c_str());
				char * replyBuf = (char*)mp2;
				sendto(fd, replyBuf, sizeof(myPacket), 0, (sockaddr *)&remaddr, addrSize);
			}
		}
	}
}


int main(void)
{
	server s;
	s.run();
}